package com.ala4.oxcafe.boot.filter;

import com.ala4.oxcafe.constants.SecurityConstants;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * 这里只是将用户名/密码的获取方案重新修正下，改为了从 JSON 中获取用户名密码
 * 剩下的流程就是标准的spring security的流程了
 *
 * @author PING
 * @version 1.0
 * @date 2025/2/18 10:11
 */
public class PasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    public PasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        // 需要是 POST 请求
        if (!SecurityConstants.METHOD_POST.equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }

        // json类型请求处理方式
        logger.debug("login ContentType " + request.getContentType());
        if (request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE)) {
            UsernamePasswordAuthenticationToken authRequest = null;
            try (InputStream is = request.getInputStream()) {
                // 通过ObjectMapper读取request中的I/O流，将JSON映射到Map上
                Map<String, String> authenticationBean = objectMapper.readValue(is, new TypeReference<Map<String, String>>() {
                });
                authRequest = UsernamePasswordAuthenticationToken.unauthenticated(authenticationBean.get(this.getUsernameParameter()), authenticationBean.get(this.getPasswordParameter()));
            } catch (IOException e) {
                logger.error("JsonUsernamePasswordAuthenticationFilter Error ", e);
                authRequest = new UsernamePasswordAuthenticationToken("", "");
            }

            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);

        } else {
            // 其他类型的请求依旧走原来的处理方式
            return super.attemptAuthentication(request, response);
        }
    }

}
